package acl

import (
	"errors"
	"gitee.com/zackeus/go-boot/freeswitch/mod/xmlcurl"
	"github.com/beevik/etree"
)

type (
	Option func(xml *Xml) error

	Xml struct {
		doc   *etree.Document
		lists *etree.Element
	}

	Node struct {
		Type string
		Cidr string
	}
)

func New(name, rule string, opts ...Option) (xmlcurl.XmlConf, error) {
	xml := &Xml{
		doc: etree.NewDocument(),
	}
	include := xml.doc.CreateElement("include")

	list := include.CreateElement("list")
	xml.lists = list

	list.CreateAttr("name", name)
	list.CreateAttr("default", rule)

	for _, opt := range opts {
		if err := opt(xml); err != nil {
			return nil, err
		}
	}

	return xml, nil
}

func WithNodes(nodes ...*Node) Option {
	return func(x *Xml) error {
		if nodes == nil {
			return nil
		}

		for _, node := range nodes {
			nodeElement := x.lists.CreateElement("node")
			nodeElement.CreateAttr("type", node.Type)
			nodeElement.CreateAttr("cidr", node.Cidr)
		}
		return nil
	}
}

func (x *Xml) BodyElement() *etree.Element {
	return x.lists
}

func (x *Xml) MarshalToXml() ([]byte, error) {
	x.doc.Indent(1)
	return x.doc.WriteToBytes()
}

func (x *Xml) UnMarshalFromString(v string) error {
	if x.doc == nil {
		x.doc = etree.NewDocument()
	}
	if err := x.doc.ReadFromString(v); err != nil {
		return err
	}

	lists := x.doc.FindElement("./include/list")
	if lists == nil {
		return errors.New("the element include/list is nil")
	}
	x.lists = lists

	return nil
}

func (x *Xml) WriteToFile(path string) error {
	x.doc.Indent(1)
	return x.doc.WriteToFile(path)
}
